﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using T2V.SharePoint.Workflow.TaskActions;
using T2V.SharePoint.Common.Models;
using T2V.SharePoint.Common.Extensions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using T2V.SharePoint.Common.Utilities;
using Microsoft.Office.Word.Server.Service;
using Microsoft.Office.Word.Server.Conversions;
using Microsoft.SharePoint.Administration;
using System.IO;
using System.Threading;
using System.Web;
using T2V.SharePoint.Common;
using Novacode;

namespace T2V.SharePoint.Workflow.TaskActions
{
    public class StampDocument : ITaskActionHandler
    {
        #region ITaskActionHandler Members
        public virtual void Execute(TaskActionArgs actionData)
        {
            try
            {
                StampDocumentSettings stampDocumentSettings = actionData.GetActionData<StampDocumentSettings>();

                if (stampDocumentSettings.Enable)
                {
                    SPWeb wfWeb = actionData.WorkflowProperties.Web;
                    Stream stampIconStream = null;

                    string iconUrl = string.Empty;

                    if (!string.IsNullOrEmpty(stampDocumentSettings.StampIconUrl))
                    {
                        if (Utility.IsAbsoluteUri(stampDocumentSettings.StampIconUrl))
                        {
                            SPSecurity.RunWithElevatedPrivileges(delegate()
                            {
                                using (SPSite site = new SPSite(stampDocumentSettings.StampIconUrl))
                                {
                                    using (SPWeb web = site.OpenWeb())
                                    {
                                        SPFile file = web.GetFile(stampDocumentSettings.StampIconUrl);
                                        if (file != null)
                                        {
                                            stampIconStream = file.OpenBinaryStream();
                                            if (stampIconStream != null)
                                            {
                                                BeginStampDocument(actionData.WorkflowProperties, stampDocumentSettings, stampIconStream);
                                            }
                                        }
                                    }
                                }
                            });
                        }
                        else
                        {
                            string fileTemplateUrl = wfWeb.ServerRelativeUrl.TrimEnd('/') + "/" + stampDocumentSettings.StampIconUrl.TrimStart('/');
                            SPSecurity.RunWithElevatedPrivileges(delegate()
                            {
                                using (SPSite site = new SPSite(wfWeb.Site.ID))
                                {
                                    using (SPWeb web = site.OpenWeb(wfWeb.ID))
                                    {
                                        SPFile file = web.GetFile(fileTemplateUrl);
                                        if (file != null)
                                        {
                                            stampIconStream = file.OpenBinaryStream();
                                            if (stampIconStream != null)
                                            {
                                                BeginStampDocument(actionData.WorkflowProperties, stampDocumentSettings, stampIconStream);
                                            }
                                        }
                                    }
                                }
                            });
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Utility.LogError(ex.Message, "StampDocument");
            }

        }
        #endregion

        private void BeginStampDocument(SPWorkflowActivationProperties wfProperties, StampDocumentSettings stampDocumentSettings, Stream stampIconStream)
        {
            SPWeb wfWeb = wfProperties.Web;
            SPListItem wfItem = wfProperties.Item;

            SPAttachmentCollection wfItemAttachments = wfItem.Attachments;

            MemoryStream stampedDocMemStream = new MemoryStream();

            foreach (string attachmentName in wfItemAttachments)
            {
                if (attachmentName.IndexOf("Original.docx", StringComparison.CurrentCultureIgnoreCase) == -1) continue;

                String attachmentAbsoluteURL = wfItemAttachments.UrlPrefix + attachmentName;
                SPFile attachmentFile = wfWeb.GetFile(attachmentAbsoluteURL);

                Stream docStream = attachmentFile.OpenBinaryStream();

                DocX originalDocument = DocX.Load(docStream);

                #region Custom Stamped
                originalDocument.AddFooters();

                Novacode.Image stamp_img = originalDocument.AddImage(stampIconStream);

                Picture stamp_pic = stamp_img.CreatePicture();
                stamp_pic.Height = 40;
                stamp_pic.Width = 40;

                Novacode.Footer footer_default = originalDocument.Footers.odd;
                Paragraph footer_paragraph = footer_default.InsertParagraph();
                footer_paragraph.AppendPicture(stamp_pic);
                footer_paragraph.Alignment = Alignment.right;

                //originalDocument.Save();
                originalDocument.SaveAs(stampedDocMemStream);
                stampedDocMemStream.Position = 0;

                #endregion
                break;
            }

            if (stampedDocMemStream != null)
            {
                switch (stampDocumentSettings.DestinationType)
                {
                    case ActionStampDocumentDestinationType.Attachment:
                        StampDocumentInAttachment(wfProperties, stampedDocMemStream);
                        break;
                    case ActionStampDocumentDestinationType.DocumentLibrary:

                        break;
                }
            }
        }

        private void StampDocumentInAttachment(SPWorkflowActivationProperties wfProperties, Stream stampedDocStream)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite site = new SPSite(wfProperties.Web.Site.ID))
                {
                    using (SPWeb web = site.OpenWeb(wfProperties.Web.ID))
                    {
                        try 
                        {
                            web.AllowUnsafeUpdates = true;

                            SPList list = web.Lists[wfProperties.ListId];

                            SPListItem listItem = list.GetItemById(wfProperties.ItemId);

                            string fileName = string.Format("{0}_{1}_Stamped.docx", listItem.Title.ConvertToValidSharePointFileName(), DateTime.Now.ToString("yyyyMMdd"));


                            using (DisableItemEvent disableEvent = new DisableItemEvent())
                            {
                                List<string> fileNames = new List<string>();

                                foreach (string file in listItem.Attachments)
                                {
                                    fileNames.Add(file);
                                }

                                foreach (string file in fileNames)
                                {
                                    listItem.Attachments.DeleteNow(file);
                                }

                                listItem.Attachments.AddNow(fileName, StreamToBytes(stampedDocStream));
                                listItem.Update();
                            }

                            wfProperties.LogToWorkflowHistory(SPWorkflowHistoryEventType.None, wfProperties.Web.CurrentUser, "Stamped this document: " + fileName, string.Empty);
                        }
                        catch(Exception ex){}
                        finally
                        {
                            web.AllowUnsafeUpdates = false;
                        }
                      
                    }
                }
            });
        }

        private void StampDocumentInDocumentLibrary()
        {

        }

        #region Methods
        private byte[] StreamToBytes(Stream stream)
        {
            long originalPosition = 0;

            if (stream.CanSeek)
            {
                originalPosition = stream.Position;
                stream.Position = 0;
            }

            try
            {
                byte[] readBuffer = new byte[4096];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                if (stream.CanSeek)
                {
                    stream.Position = originalPosition;
                }
            }
        }
        #endregion Methods
    }
}
